﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RenderEngineInterfaces;
using System.ComponentModel.Composition;
using System.IO;
using System.Threading.Tasks;
using DeepZoomPivotConstructor.VisualLib;
using IndicoInterface.SimpleAgendaDataModel;
using System.Net;
using DeepZoomPivotConstructor.VisualLib.Hotspots;

namespace IndicoRender
{
    /// <summary>
    /// Renders a single talk. THis is mostly forwarding a URI to be
    /// rendered by someone else! :-)
    /// </summary>
    [Export(typeof(IRenderItem))]
    [RenderInfo(typeof(Talk))]
    public class RenderIndicoTalk : IRenderItem
    {

        /// <summary>
        /// So we can do a render or two...
        /// </summary>
        [Import(typeof(IRenderEngine))]
        private IRenderEngine RenderMe { get; set; }

        /// <summary>
        /// If we should be using a different temp directory than the one that is there by default... :-)
        /// </summary>
        [Import("RenderingTempDir", AllowDefault = true)]
#pragma warning disable 0649
        private DirectoryInfo RenderingTempDir;
#pragma warning restore 0649

        /// <summary>
        /// Helps with laying out everyone!
        /// </summary>
        [Import]
        private ILayoutHelper LayMeOut { get; set; }

        /// <summary>
        /// Forward the url to be rendered by someoene lse in the
        /// system. Then put together the meta-data that is required.
        /// </summary>
        /// <param name="what"></param>
        /// <returns></returns>
        public Task<Visual> Render(object what)
        {
            return Task<Visual>.Factory.StartNew(() =>
                {
                    return RenderATalk(what as Talk);
                });
        }

        /// <summary>
        /// Do the actual rendering of the talk (perhaps on a
        /// backgroudn thread!). We are also responsible for rendering sub talks, etc.
        /// We arrange it so the main talk is larger than the sub-talks, if we have a main talk...
        /// </summary>
        /// <param name="talk"></param>
        /// <returns></returns>
        private Visual RenderATalk(Talk talk)
        {
            if (talk == null)
            {
                return null;
            }

            ///
            /// Do the main talk
            /// 

            Visual mainTalk = null;
            if (talk.SlideURL != null)
            {
                Uri u = new Uri(talk.SlideURL);
                mainTalk = RenderMe.Render(u, new Type[] { typeof(RenderIndicoWebSite) }, forceAsComposableUnit: true);
                if (mainTalk != null)
                {
                    IndicoRenderUtilities.getSizeRight(mainTalk);
                }
            }

            ///
            /// Do the sub-talks
            /// 

            Visual subTalks = null;
            if (talk.SubTalks != null)
            {
                var subt = (from st in talk.SubTalks
                            where st.SlideURL != null
                            let r = RenderMe.RenderToFuture(st)
                            where r != null
                            select new
                            {
                                rendered = r,
                                subtalk = st
                            }).ToArray();

                Task<Visual>.WaitAll((from sb in subt select sb.rendered).ToArray());

                var reneredTalks = (from st in subt
                                   let t = st.rendered.Result
                                   where t != null
                                   select st).ToArray();
                if (reneredTalks.Any())
                {
                    var talksWithTitles = from st in reneredTalks
                                          select new VisualTitleAndBackground(IndicoRenderUtilities.getSizeRight(st.rendered.Result), RenderingTempDir) { { 0.5, st.subtalk.Title, new HSActionLink(new Uri(st.subtalk.SlideURL)) } };
                    subTalks = LayMeOut.LayoutIn2By3Rows(talksWithTitles);
                }
            }

            ///
            /// Put it all together. Note the hinky code below
            /// in order ot make sure that Visual is mainTalk - we don't
            /// add an extra layer - if we don't need it.
            /// 

            if (subTalks == null && mainTalk == null)
            {
                return null;
            }

            VisualHolder resulth = new VisualHolder();
            Visual result = resulth;

            if (mainTalk != null)
            {
                if (subTalks != null)
                {
                    resulth.AddImage(mainTalk);
                }
                else
                {
                    result = mainTalk;
                }
            }

            if (subTalks != null)
            {
                if (mainTalk != null)
                {
                    subTalks.ScaleToWidth(mainTalk.Width);
                    subTalks.YPosition = mainTalk.Height + 0.2;
                }
                else
                {
                    IndicoRenderUtilities.getSizeRight(subTalks);
                }
                resulth.AddImage(subTalks);
            }

            ///
            /// Now, make sure to mark everythign.
            /// 

            result.Info = new Visual.VisualInfo()
            {
                Title = talk.Title,
                Info = new string[] { IndicoRenderUtilities.TimeSpanToString(talk.StartDate, talk.EndDate) }
            };

            if (talk.TalkType == TypeOfTalk.ExtraMaterial)
            {
                result.Info.Info[0] = "Extra Material";
            }

            IndicoRenderUtilities.getSizeRight(result);

            return result;
        }

        /// <summary>
        /// The agent string we use in URI requests!
        /// </summary>
        [Import("HttpAgentString")]
        private string HttpAgentString { get; set; }

        /// <summary>
        /// If this what is a string that is a valid path pointing to a real file, then
        /// we can go for it! But only generically. :-) All we need is *something* that
        /// can be rendered and we are good to go.
        /// </summary>
        /// <param name="what"></param>
        /// <returns></returns>
        public RenderPluginPriority RenderPriority(object what)
        {
            Talk t = what as Talk;

            ///
            /// Try the main slide url to see if we can render that...
            /// 

            if (t.SlideURL != null)
            {
                try
                {
                    Uri u = new Uri(t.SlideURL);
                    return RenderPluginPriority.RPPGeneric;
                }
                catch
                {
                }
            }

            if (t.SubTalks != null)
            {
                var canDo = (from st in t.SubTalks where RenderPriority(st) != RenderPluginPriority.RPPCantDoIt select st).Any();
                if (canDo)
                    return RenderPluginPriority.RPPGeneric;
            }

            return RenderPluginPriority.RPPCantDoIt;
        }
    }
}
